home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Sample Code / Printing Samples / Printer Drivers… / LaserWriterIISC / UniversalMessageIntf.c < prev    next >
Encoding:
Text File  |  1993-09-13  |  61.8 KB  |  1,963 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     UniversalMessageIntf.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which override the universal imaging 
  7.     messages that the LaserWriter SC utilizes.
  8.     
  9.     9/13/93 - dmh - Updated for the b2 seed.
  10.         
  11. COPYRIGHT
  12.     Copyright Apple Computer, Inc. 1989-1992
  13.     All rights reserved. 
  14.     
  15. INTERFACE ROUTINES:
  16.     SD_Initialize
  17.     SD_ShutDown
  18.     SD_DefaultPrinter
  19.     SD_DespoolPage
  20.     SD_SetupImageData
  21.     SD_OpenConnection
  22.     SD_CloseConnection
  23.     SD_StartSendPage
  24.     SD_FinishSendPage
  25.     SD_WriteData
  26.     SD_CheckStatus
  27.     SD_GetDeviceStatus
  28.     SD_CreateImageFile
  29.     SD_RasterDataIn
  30.  
  31. -------------------------------------------------------------------------------- */
  32.  
  33. // Include the standard Mac header files 
  34. #include "MacIncludes.h"
  35.  
  36. // Include the new QuickDraw GX graphics header files 
  37. #include <graphics routines.h>
  38. #include <graphics libraries.h>
  39. #include <math routines.h>
  40. #include <qd library.h>
  41.  
  42. // Include the required Printing Manager header files 
  43. #include <PrintingManager.h>
  44. #include <PrintingMessages.h>
  45. #include <PrintingDrivers.h>
  46. #include <Collections.h>
  47. #include <Messages.h>
  48. #include <PrintingResTypes.h>
  49. #include <PrintingErrors.h>
  50.  
  51. #include <Exceptions.h>
  52.  
  53. // Include the internal driver constants and types used by this module 
  54. #include "Resources.h"
  55. #include "UniversalMessageIntf.h"
  56. #include "LaserSCIntf.h"
  57. #include "SCPrinterStatus.h"
  58.  
  59.  
  60. /***************************************************************************************
  61. *                                         INTERNAL ROUTINES                                                     *
  62. ***************************************************************************************/                        
  63.  
  64. /****************************************************************************************
  65.  
  66.                             FixRoundRectangle
  67.                             
  68.     function:
  69.                 This routine is a utility function which rounds the coordinate values within 
  70.                 the gxRectangle passed in.
  71.                 
  72.     parameters:                
  73.                 r            gxRectangle whose coordinates are to be rounded
  74.                 
  75.     returns:
  76.                 None
  77.     
  78. ****************************************************************************************/
  79. void FixRoundRectangle(gxRectangle *r)
  80. {
  81.     r->top         = ff(FixRound(r->top));
  82.     r->left     = ff(FixRound(r->left));
  83.     r->bottom     = ff(FixRound(r->bottom));
  84.     r->right     = ff(FixRound(r->right));
  85. }
  86. /* FixRoundRectangle */
  87.  
  88.  
  89. /****************************************************************************************
  90.  
  91.                             AlignPage
  92.                             
  93.     function:
  94.                 This routine is called to adjust the raster imaging system's page size
  95.                 gxRectangle so that it's zero based and long word aligned.
  96.                 It also returns a QuickDraw device gxRectangle which represents the page
  97.                 centered (left to right) in the SC's imaging area.  The device gxRectangle is 
  98.                 used to set the margins on the printer in SD_StartSendPage.
  99.                 
  100.     parameters:    
  101.                 pageBounds        raster imaging system's pageSize rect
  102.                 deviceRect        gxRectangle representing the device gxRectangle for the LWSC
  103.                 maxPageHeight    maximum height allowed for the pageBounds and deviceRect rectangles
  104.                 
  105.     returns:
  106.                 None
  107.     
  108. ****************************************************************************************/
  109. void AlignPage(gxRectangle *pageBounds, Rect *deviceRect, Fixed maxPageHeight)
  110. {
  111.     gxRectangle            tempBounds;
  112.     Fixed                leftMargin;
  113.     Fixed                width;
  114.     short                leftEdge;
  115.     Fixed                paperWidth;
  116.     
  117.     // First force the pageBounds gxRectangle to be zero based.
  118.  
  119.     pageBounds->right -= pageBounds->left;
  120.     pageBounds->left = ff(0);
  121.     pageBounds->bottom -= pageBounds->top;
  122.     pageBounds->top = ff(0);
  123.  
  124.     // Force the page size gxRectangle's width to be within the max. range 
  125.     if (pageBounds->right > kMaxPageWidth)
  126.         pageBounds->right = kMaxPageWidth;
  127.     
  128.     // Force the page size gxRectangle's height to be within the max. range
  129.     
  130.     if (pageBounds->bottom > maxPageHeight)
  131.         pageBounds->bottom = maxPageHeight;
  132.  
  133.     // Force the page to be long-aligned because the offscreen code forces long alignment. 
  134.     // We do this by long aligning the page width, and then resetting the left and 
  135.     // right edges. 
  136.     
  137.     width = ( (pageBounds->right + ff(31)) >> (5+16)) << (5+16);
  138.     
  139.     pageBounds->right = width;
  140.     FixRoundRectangle(pageBounds);
  141.     
  142.     // Now we create the deviceRect starting with the adjusted pageSize gxRectangle 
  143.     tempBounds = *pageBounds;
  144.     
  145.     // Center the page (left to right) on the engine.  The top margin is always the minimum margin 
  146.  
  147.     tempBounds.top += kMinSCTopMargin;
  148.     tempBounds.bottom += kMinSCTopMargin;
  149.  
  150.     paperWidth = pageBounds->right - pageBounds->left;
  151.     leftMargin = (kMaxPaperWidth - paperWidth) >> 1;
  152.     leftEdge = (((leftMargin >> 16) + 7 ) >> 3) << 3;    // ( (margin + 7) / 8) * 8
  153.     tempBounds.left = ff(leftEdge);
  154.     tempBounds.right = tempBounds.left + width;
  155.     
  156.     FixRoundRectangle(&tempBounds);
  157.     FixedRectToShort(&tempBounds, deviceRect);
  158. }
  159. /* AlignPage */
  160.  
  161.  
  162. /****************************************************************************************
  163.  
  164.                             UpdatePaperFeed
  165.                             
  166.     function:
  167.                 This routine is a utility routine for updating the auto-feed setting of the
  168.                 job.
  169.                 
  170.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  171.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  172.                 
  173.     parameters:
  174.                 theJob        the gxJob whose auto-feed boolean is to be set
  175.                 autoFeedOn    true => switch job to auto-feed; false => switch to manual feed
  176.                 
  177.     returns:
  178.                 OSErr
  179.  
  180. ****************************************************************************************/
  181. OSErr UpdatePaperFeed(gxJob theJob, Boolean autoFeedOn)
  182. {
  183.     OSErr            anErr;
  184.     Collection        jobCollection = GXGetJobCollection(theJob);
  185.  
  186.     anErr = AddCollectionItem ( jobCollection,
  187.                                  gxPaperFeedTag,
  188.                                  gxPrintingTagID,
  189.                                  1,
  190.                                  &autoFeedOn);
  191.  
  192.     check(anErr == noErr);
  193.     return(anErr);
  194. }
  195. /* UpdatePaperFeed */
  196.  
  197.  
  198. /****************************************************************************************
  199.  
  200.                             RetrieveJobItem
  201.                             
  202.     function:
  203.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  204.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  205.  
  206.     parameters:                
  207.  
  208.     returns:
  209.  
  210. ****************************************************************************************/
  211. OSErr    RetrieveJobItem( gxJob theJob, CollectionTag tag, long id, void *theValue, long *itemSize )
  212. {
  213.     OSErr    anErr = noErr;
  214.     Collection    theCollection = GXGetJobCollection( theJob );
  215.  
  216.     anErr = GetCollectionItem (theCollection,
  217.                                 tag,
  218.                                 id,
  219.                                 itemSize,
  220.                                 theValue );
  221.  
  222.     return( anErr );
  223.  
  224. }
  225. /* RetrieveJobItem */
  226.  
  227.  
  228. /****************************************************************************************
  229.  
  230.                             RetrievePaperFeed
  231.                             
  232.     function:
  233.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  234.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  235.     
  236.     parameters:
  237.     
  238.     returns:
  239.  
  240. ****************************************************************************************/
  241. OSErr    RetrievePaperFeed(gxJob theJob, Boolean *autoFeedOn, Boolean *feedLocked)
  242. {
  243.     #pragma unused (feedLocked)
  244.     
  245.     long    paperFeedSize = 1;
  246.  
  247.     return( RetrieveJobItem(     theJob, 
  248.                                 gxPaperFeedTag, 
  249.                                 gxPrintingTagID, 
  250.                                 autoFeedOn, 
  251.                                 &paperFeedSize ) );
  252.  
  253. }
  254. /* RetrievePaperFeed */
  255.  
  256.  
  257. /****************************************************************************************
  258.  
  259.                             RetrieveManualFeedPaper
  260.                             
  261.     function:
  262.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  263.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  264.  
  265.     parameters:                
  266.  
  267.     returns:
  268.  
  269. ****************************************************************************************/
  270. OSErr RetrieveManualFeedPaper(gxJob theJob, gxManualFeedInfo **paperTypeNameList)
  271. {
  272.     OSErr            anErr;
  273.     Collection        jobCollection = GXGetJobCollection(theJob);
  274.     Size            ptrSize;
  275.     
  276.     anErr = GetCollectionItemInfo(jobCollection, gxManualFeedTag, gxPrintingTagID,
  277.                                             0, &ptrSize, 0);
  278.     
  279.     
  280.     if (anErr == noErr) {
  281.     
  282.         *paperTypeNameList = (gxManualFeedInfo *) NewPtrClear(ptrSize);
  283.         anErr = MemError();
  284.         nrequire( anErr, NewPtrClearFails );
  285.  
  286.         anErr = GetCollectionItem( jobCollection, 
  287.                                     gxManualFeedTag, 
  288.                                     gxPrintingTagID, 
  289.                                     NULL,
  290.                                     *paperTypeNameList); 
  291.         }
  292.  
  293. NewPtrClearFails:
  294.     return( anErr );
  295. }
  296. /* RetrieveManualFeedPaper */
  297.  
  298.  
  299. /****************************************************************************************
  300.  
  301.                             IsManualFeedPaperType
  302.                             
  303.     function:
  304.                 NOTE: THIS UTILITY ROUTINE NEEDS TO BE MOVED TO THE PUBLIC INTERFACE SO WE
  305.                 DON'T NEED TO INCLUDE IT HERE IN THIS DRIVER.  IT CAME FROM DIALOGUTILITIES.C.
  306.     
  307.     parameters:
  308.     
  309.     returns:
  310.  
  311. ****************************************************************************************/
  312. OSErr    IsManualFeedPaperType(gxPaperType thePaperType, Boolean *IsManualFeed)
  313. {
  314.     OSErr                anErr;
  315.     gxJob                theJob = GXGetJob();
  316.     Boolean                fAutoFeedOn;
  317.     gxManualFeedInfo     *paperTypeNameList = nil;
  318.     short                nameCount, idx;
  319.     Str31                paperName;
  320.  
  321.     *IsManualFeed    = false;
  322.     anErr = RetrievePaperFeed( theJob, &fAutoFeedOn, nil );
  323.     nrequire( anErr, RetrievePaperFeedFails );
  324.     
  325.     if ( !fAutoFeedOn ) {
  326.  
  327.         anErr = RetrieveManualFeedPaper( theJob, &paperTypeNameList );
  328.         
  329.         if (anErr == collectionItemNotFoundErr) {
  330.         
  331.             *IsManualFeed = true;
  332.             anErr = noErr;
  333.             
  334.         } else {
  335.         
  336.             nrequire( anErr, RetrieveManualFeedPaperFails );
  337.             
  338.             GXGetPaperTypeName( thePaperType, paperName );
  339.             nameCount = paperTypeNameList->numPaperTypeNames;
  340.             
  341.             for (idx = 0; idx < nameCount; ++idx) {
  342.  
  343.                 Ptr pName = &paperTypeNameList->paperTypeNames[idx];
  344.                 
  345.                 if ( IUMagIDString(    paperName, 
  346.                                             pName,
  347.                                             paperName[0] + 1,
  348.                                             *pName + 1)     == 0  ) {
  349.                     *IsManualFeed = true;
  350.                     break;
  351.                     }
  352.                 }
  353.             }
  354.         }
  355.  
  356.     
  357. RetrieveManualFeedPaperFails:
  358.  
  359.     if ( paperTypeNameList != nil )
  360.         DisposPtr( (Ptr) paperTypeNameList );
  361.         
  362. RetrievePaperFeedFails:
  363.  
  364.     return( anErr );
  365. }
  366. /* IsManualFeedPaperType */
  367.  
  368.  
  369. /****************************************************************************************
  370.  
  371.                             JobIsBestQuality
  372.                             
  373.     function:
  374.                 This routine is called to determine if the job the driver is currently
  375.                 processing is to be output in best quality or rough quality. The function
  376.                 returns true if best quality, and false otherwise.
  377.                 
  378.     parameters:    
  379.                 None
  380.                 
  381.     returns:
  382.                 Boolean        true if best quality job; false otherwise
  383.     
  384. ****************************************************************************************/
  385. Boolean JobIsBestQuality(void)
  386. {
  387.     OSErr                anErr;
  388.     Boolean                isFinal;
  389.     gxQualityInfo        jobQualitySettings;
  390.     long                itemSize = sizeof(jobQualitySettings);
  391.  
  392.     // Retrieve the quality setting info from the job
  393.     anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
  394.     check(anErr == noErr);
  395.     
  396.     isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
  397.  
  398.     return(isFinal);
  399. }
  400. /* JobIsBestQuality */
  401.  
  402.  
  403. /****************************************************************************************
  404.  
  405.                             SC_HandleManualFeed
  406.                             
  407.     function:
  408.                 This routine is called at FinishSendPage time when the user needs to be
  409.                 prompted to place the correct paper into the printer for a manual feed
  410.                 job.  This routine calls ResolvePrinterProblem to prompt the user
  411.                 and field his responses.  If the user decides to abort the print job, then
  412.                 this routine will return an error of gxPrUserAbortErr.  If the problem
  413.                 is resolved successfully, then this routine returns noErr.
  414.                 
  415.     parameters:    
  416.                 thePaperType        the Paper Type that should be loaded into the printer
  417.                 
  418.     returns:
  419.                 OSErr
  420.     
  421. ****************************************************************************************/
  422. OSErr SC_HandleManualFeed(gxPaperType thePaperType)
  423. {
  424.     OSErr        anErr;
  425.     short        dialogResult;
  426.     long        printerProblem;
  427.  
  428.     // Set printerProblem to indicate the type of problem encountered 
  429.     
  430.     SetPrinterProblemStatResIndex(kOutOfPaperStatIdx, &printerProblem);
  431.     SetPrinterProblemStatResID(kTransmissionStatID, &printerProblem);
  432.  
  433.     // Prompt the user to put paper into the printer.  This routine will return anErr of 
  434.     // gxPrUserAbortErr if the user aborts the print job. 
  435.     
  436.     anErr = ResolvePrinterProblem(printerProblem, isManualFeed, thePaperType, &dialogResult);
  437.     require(anErr == noErr, ResolvePrinterProblem);
  438.     
  439.     switch (dialogResult)
  440.     {
  441.         case nil:
  442.         case ok:
  443.             // User loaded the paper and may or may not have clicked OK by the time we discovered 
  444.             // that the printer now has paper. 
  445.             break;
  446.             
  447.         case gxAutoFeedButtonId:
  448.             // User wishes to do the remainder of the job using the paper cassette. Update job to 
  449.             // relfect auto-feed and tell the printer to feed paper from the cassette. 
  450.             
  451.             (void) UpdatePaperFeed(GXGetJob(), true);
  452.  
  453.             // Tell printer to switch to paper feed from the cassette 
  454.             anErr = LaserSC_SetBuffandFeedMode(    !isManualFeed, //    T => do manual feed; F => auto-feed
  455.                                                             true);            // T => do buffered printing; F => wait for Print command to complete
  456.             require(anErr == noErr, LaserSC_SetBuffandFeedMode);
  457.             
  458.             break;
  459.  
  460.         default:
  461.             check(0);
  462.             break;
  463.     }
  464.  
  465.     
  466. /******* Clean-up *******/
  467.  
  468. LaserSC_SetBuffandFeedMode:
  469. ResolvePrinterProblem:        
  470.     return(anErr);
  471. }
  472. /* SC_HandleManualFeed */
  473.  
  474.  
  475. /********************************************************************************************
  476.  
  477.                                         GenTIBProgram
  478.     function:
  479.                     GenTIBProgram creates a generic Transfer Instruction Block program which is used to
  480.                     perform all SCSI data transfer operations (refer to SCSI Manager documentation for
  481.                     info. on TIB's). It uses the function's parameters to customize the data transfer
  482.                     operations of the TIB program.
  483.     
  484.     parameters:
  485.                     tibProgram                Pointer to the TIB program generated (returned)
  486.                     dataBuffer                Pointer to buffer to be used for input or output data xfer
  487.                     bytesToXfer                Total number of bytes to send or receive
  488.                     bytesPerChunk            Number of bytes to send or receive in each chunk (during TIB transfer)
  489.     
  490.     returns:
  491.                     None
  492.                     
  493. ********************************************************************************************/
  494. void GenTIBProgram(SCSIInstr    tibProgram[], 
  495.                      Ptr            dataBuffer, 
  496.                      long            bytesToXfer, 
  497.                      long            bytesPerChunk)
  498. {    
  499.     long        numChunks;
  500.     long        numRemBytes;
  501.     
  502.     numChunks = bytesToXfer / bytesPerChunk;        // Integral number of byte chunks to send
  503.     numRemBytes = bytesToXfer % bytesPerChunk;    //    Leftover characters to be sent/received
  504.  
  505.                                                                                             //        Program starts here
  506.     tibProgram[0].scOpcode = scLoop;                                                //        count -= 1
  507.     tibProgram[0].scParam1 = 60;                                                    //        if count > 0 then goto A
  508.     tibProgram[0].scParam2 = numChunks + 1;
  509.     
  510.     tibProgram[1].scOpcode = scLoop;                                                // C:    count -= 1
  511.     tibProgram[1].scParam1 = 20;                                                    //        if count > 0 then goto B
  512.     tibProgram[1].scParam2 = numRemBytes + 1;
  513.     
  514.     tibProgram[2].scOpcode = scStop;                                                //        Terminate program
  515.     tibProgram[2].scParam1 = 0;
  516.     tibProgram[2].scParam2 = 0;
  517.     
  518.     tibProgram[3].scOpcode = scMove;                                                //    B:    Place current dataBuffer pointer into next
  519.     tibProgram[3].scParam1 = (unsigned long) &tibProgram[6].scParam1;    //        instruction
  520.     tibProgram[3].scParam2 = (unsigned long) &tibProgram[4].scParam1;
  521.     
  522.     tibProgram[4].scOpcode = scNoInc;                                            //        Perform data xfer to/from dataBuffer for numRemBytes
  523.     tibProgram[4].scParam1 = (unsigned long) dataBuffer;                    //        Address is set by previous scMove instruction
  524.     tibProgram[4].scParam2 = numRemBytes;
  525.     
  526.     tibProgram[5].scOpcode = scStop;                                                //        Terminate the program
  527.     tibProgram[5].scParam1 = 0;
  528.     tibProgram[5].scParam2 = 0;
  529.             
  530.     tibProgram[6].scOpcode = scInc;                                                //    A:    Perform data xfer to/from dataBuffer for bytesPerChunk
  531.     tibProgram[6].scParam1 = (unsigned long) dataBuffer;                    //        dataBuffer += bytesPerChunk
  532.     tibProgram[6].scParam2 = bytesPerChunk;
  533.     
  534.     tibProgram[7].scOpcode = scLoop;                                                //        count -= 1; 
  535.     tibProgram[7].scParam1 = -10;                                                    //        if count > 0 then goto A
  536.     tibProgram[7].scParam2 = numChunks;
  537.     
  538.     tibProgram[8].scOpcode = scLoop;                                                //        goto C
  539.     tibProgram[8].scParam1 = -70;                                                    //        
  540.     tibProgram[8].scParam2 = 2;
  541. }
  542. /* GenTIBProgram */
  543.  
  544.  
  545. /********************************************************************************************
  546.  
  547.                                         WaitForPageToPrint
  548.     function:
  549.                     WaitForPageToPrint is called to force the current printer's page buffer to be
  550.                     printed.  It handles all error conditions and alerts the user as necessary.  This
  551.                     routine will return when the page has been printed, the user aborted the job, or
  552.                     some fatal printer error was encountered.  This routine assumes we've already started
  553.                     the page printing by an earlier call to LaserSC_PrintPage (performed in the
  554.                     SD_FinishSendPage routine).
  555.     
  556.     parameters:
  557.                     manualFeed            true => paper is being manually fed; false => paper is auto-fed
  558.                     thePaperType        paper type of the paper that should be in the printer
  559.     returns:
  560.                     OSErr
  561.                     
  562. ********************************************************************************************/
  563. OSErr WaitForPageToPrint(    Boolean        manualFeed,
  564.                             gxPaperType    thePaperType) 
  565. {    
  566.     OSErr        anErr = noErr;
  567.     short        deviceStatus;
  568.     
  569.     // Continue looping until the page is printed, the user aborts, or a fatal error occurs
  570.     
  571.     while (true)
  572.     {
  573.         // Now we must wait until the device is no longer busy (page printed OK) or some problem occurred
  574.         do
  575.         {
  576.             // Get the latest status info from the printer
  577.             
  578.             anErr = LaserSC_GetDeviceStatus(&deviceStatus);
  579.             require(anErr == noErr, LaserSC_GetDeviceStatus);
  580.             
  581.             // Let the client app have a chance to run
  582.             anErr = GXJobIdle();
  583.             require(anErr == noErr, JobIdleFails);
  584.         }
  585.         while (deviceStatus == kBusy);
  586.  
  587.         // If the device is now ready, then the page must have printed without error 
  588.         if (deviceStatus == kGoodCondition)
  589.         {
  590.             break;
  591.         }
  592.         else    // Device is not ready; see what problem it may have 
  593.         {
  594.             long        printerProblem;
  595.         
  596.             // Status the printer to determine the problem it's experiencing 
  597.  
  598.             anErr = FindPrinterProblem(&printerProblem, nil);
  599.             require(anErr == noErr, FindPrinterProblem);
  600.  
  601.             // If the printer is out of paper and we're doing a manual feed job, then alert 
  602.             // the user to put paper into the printer. 
  603.  
  604.             if ( (GetStatResIndex(printerProblem) == kOutOfPaperStatIdx) && manualFeed )
  605.             {
  606.                 // Tell the user to put in the paper 
  607.                 anErr = SC_HandleManualFeed(thePaperType);
  608.                 
  609.                 // If the error returned is gxPrUserAbortErr, then the user has cancelled the print job 
  610.                 if (anErr != gxPrUserAbortErr)
  611.                 {
  612.                     // If no other error has occurred, then we loop around and try to re-print the page 
  613.                     require(anErr == noErr, SC_HandleManualFeed);
  614.                 }
  615.                 else    // User canceled manual feed dialog => print job has been cancelled 
  616.                     break;
  617.             }
  618.             else    // Printer is experiencing some other problem; prompt user to resolve it 
  619.             {
  620.                 short        dialogResult;
  621.  
  622.                 anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
  623.                 require(anErr == noErr, ResolvePrinterProblem);
  624.             }
  625.  
  626.             // If we get here, the printer problem has been corrected so we need to re-issue the
  627.             // print command. 
  628.     
  629.             anErr = LaserSC_PrintPage(    false,             // T => print at 8 page per minute rate; F => print normal rate
  630.                                                 false);             // T => clear printer's page buffer while printing; F => don't clear buffer
  631.             require(anErr == noErr, LaserSC_PrintPage);
  632.         }
  633.     } // while 
  634.  
  635.  
  636. /******* Clean-up *******/
  637.  
  638. LaserSC_PrintPage:
  639. ResolvePrinterProblem:
  640. SC_HandleManualFeed:
  641. FindPrinterProblem:
  642. JobIdleFails:
  643. LaserSC_GetDeviceStatus:
  644.     return(anErr);
  645. }
  646. /* WaitForPageToPrint */
  647.  
  648.  
  649. /***************************************************************************************
  650. *                                         INTERFACE ROUTINES                                                     *
  651. ***************************************************************************************/                        
  652.  
  653. /****************************************************************************************
  654.  
  655.                             SD_Initialize
  656.                             
  657.     function:
  658.                 This routine is called when a new job is created to perform some job-oriented
  659.                 task, such as conducting dialogs, spooling, and imaging.  It allocates the
  660.                 driver's globals handle and initializes it.
  661.                 
  662.     parameters:    
  663.                 None
  664.                 
  665.     returns:
  666.                 OSErr
  667.     
  668. ****************************************************************************************/
  669. OSErr SD_Initialize(void)
  670. {
  671.     OSErr                 anErr;
  672.     SpecGlobalsHdl     hGlobals;
  673.     
  674.     // Allocate the driver's global handle 
  675.  
  676.     hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
  677.     anErr = MemError();
  678.     require(anErr == noErr, NewHandleClear);
  679.     
  680.     // Tell the Printing Manager to save our globals handle for us 
  681.     SetMessageHandlerInstanceContext(hGlobals);
  682.  
  683.     return(anErr);
  684.     
  685.     
  686. /******* Clean-up *******/
  687.  
  688. NewHandleClear:
  689.     return(anErr);
  690. }
  691. /* SD_Initialize */
  692.  
  693.  
  694. /****************************************************************************************
  695.  
  696.                             SD_ShutDown
  697.                             
  698.     function:
  699.                 This routine is called when a job-oriented task has completed and the 
  700.                 message chain is being destroyed.  This routine disposes of the driver's
  701.                 globals handle..
  702.                 
  703.     parameters:        
  704.                 None
  705.                 
  706.     returns:
  707.                 OSErr
  708.     
  709. ****************************************************************************************/
  710. OSErr SD_ShutDown(void)
  711. {
  712.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  713.     
  714.     // Dump the driver's globals handle if it was allocated 
  715.  
  716.     if (hGlobals != nil)
  717.         DisposHandle((Handle) hGlobals);
  718.     
  719.     // Make sure the Printing Manager no longer has a reference to our globals handle 
  720.     SetMessageHandlerInstanceContext(nil);
  721.         
  722.     return(noErr);
  723. }
  724. /* SD_ShutDown */
  725.  
  726.  
  727. /****************************************************************************************
  728.  
  729.                             SD_DefaultPrinter
  730.                             
  731.     function:
  732.                 This routine is called when a new printer object is being created as a
  733.                 result of someone having called NewJob.  This message gives the driver the
  734.                 opportunity to add any information we want to the new printer object.  In
  735.                 this case, we add a new gxViewDevice to the printer object which will allow
  736.                 the client application to format a document for this specific device.
  737.                 
  738.     parameters:                
  739.                 thePrinter        the newly allocated printer object
  740.     returns:
  741.                 OSErr
  742.                 
  743. ****************************************************************************************/
  744. OSErr SD_DefaultPrinter(gxPrinter thePrinter)
  745. {
  746.     OSErr             anErr;
  747.     gxViewDevice     vd;
  748.     gxMapping        vdMapping;
  749.     gxShape            theBitmap;
  750.     gxColorSet        theColorSet;
  751.     
  752.     // First we let others in the chain default the printer object before we do. 
  753.  
  754.     anErr = Forward_GXDefaultPrinter(thePrinter);
  755.     require(anErr == noErr, Forward_GXDefaultPrinter);
  756.     
  757.     // Create the new gxViewDevice using a fake gxBitmap 
  758.     {
  759.         gxBitmap    aBitmap;
  760.         
  761.         aBitmap.pixelSize    = 1;
  762.         aBitmap.rowBytes    = 0;
  763.         aBitmap.width        = 0;
  764.         aBitmap.height        = 0;
  765.         aBitmap.image        = nil;
  766.         aBitmap.space        = gxNoSpace;
  767.         aBitmap.set            = nil;
  768.         aBitmap.profile    = nil;
  769.         
  770.         theBitmap = GXNewBitmap(&aBitmap, nil);
  771.         require_action( GXGetGraphicsError(nil) == noErr, GXNewBitmap, anErr = GXGetGraphicsError(nil); );
  772.         
  773.         vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
  774.         require_action( GXGetGraphicsError(nil) == noErr, GXNewViewDevice, anErr = GXGetGraphicsError(nil); );
  775.     }
  776.     
  777.     // Now set the view device's color space to be a 1-bit deep indexed space, with two entries (black and white) 
  778.     {
  779.         gxSetColor        theColors[2];
  780.         gxSetColor        *pColor;
  781.         
  782.         pColor = &theColors[0];
  783.         
  784.         // Assign the black and white rgb colors to the indexed color set 
  785.  
  786.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;            // white 
  787.         pColor++;
  788.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;            // black 
  789.         
  790.         theColorSet = GXNewColorSet(gxRGBSpace, 2, theColors);
  791.         require_action( GXGetGraphicsError(nil) == noErr, GXNewColorSet, anErr = GXGetGraphicsError(nil); );
  792.  
  793.         SetViewDeviceColorSet(vd, theColorSet);
  794.         require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
  795.     }
  796.     
  797.     // Change the gxViewDevice gxMapping to include the scaling factor from 72dpi (screen) to 300 dpi (device). 
  798.     {
  799.         Fixed        xScale;
  800.         Fixed        yScale;
  801.  
  802.         xScale = FixRatio(kHorizHighRes, 72);
  803.         yScale = FixRatio(kVertHighRes, 72);
  804.         
  805.         ResetMapping(&vdMapping);
  806.         ScaleMapping(&vdMapping, xScale, yScale, ff(0), ff(0));
  807.         
  808.         GXSetViewDeviceMapping(vd, &vdMapping);
  809.     }
  810.     
  811.     // Add the newly created gxViewDevice to the printer object 
  812.  
  813.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  814.     require_action( GXGetGraphicsError(nil) == noErr, GXAddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
  815.     
  816.     // Dispose of the temporary shapes we created along the way 
  817.  
  818.     GXDisposeShape(theBitmap);
  819.     GXDisposeColorSet(theColorSet);
  820.     
  821.     return(anErr);
  822.     
  823.     
  824. /******* Clean-up *******/
  825.  
  826. GXAddPrinterViewDevice:
  827.     GXDisposeViewDevice(vd);
  828.  
  829. SetViewDeviceColorSet:
  830.     GXDisposeColorSet(theColorSet);
  831.     
  832. GXNewColorSet:
  833. GXNewViewDevice:
  834.     GXDisposeShape(theBitmap);
  835.  
  836. GXNewBitmap:
  837. Forward_GXDefaultPrinter:
  838.     return(anErr);
  839. }
  840. /* SD_DefaultPrinter */
  841.  
  842.  
  843. /****************************************************************************************
  844.  
  845.                             SD_DespoolPage
  846.                             
  847.     function:
  848.                 This routine is called by the Printing Manager when it despools the next
  849.                 page to be imaged.  We intercept this message to adjust the raster imaging
  850.                 system's pageSize gxRectangle so that it's zero based and long aligned.  We
  851.                 Also compute the LaserWriter SC's device gxRectangle so we can use it to set
  852.                 the SC's margins in SD_StartSendPage.
  853.                 
  854.     parameters:                
  855.                 theSpoolFile        the spool file reference
  856.                 pageNum                number of the page being despooled
  857.                 theFormat            format of the despooled page
  858.                 thePage                the graphics gxShape representing the page
  859.                 formatChanged        returns true if we've changed the format; false otherwise
  860.                 
  861.     returns:
  862.                 OSErr
  863.     
  864. ****************************************************************************************/
  865. OSErr SD_DespoolPage (gxSpoolFile theSpoolFile, long pageNum,
  866.                       gxFormat theFormat, gxShape *thePage, Boolean *formatChanged)
  867. {
  868.     OSErr                     anErr;
  869.     gxRasterImageDataHdl    hImageData;
  870.     Rect                     deviceRect;
  871.     gxRectangle                pageSize;
  872.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  873.     gxRectangle                paperSize;
  874.     gxJob                    theJob = GXGetJob();
  875.     Fixed                    maxPageHeight;
  876.     
  877.     // Let the Printing Manager despool the page successfully before we continue 
  878.  
  879.     anErr = Forward_GXDespoolPage(theSpoolFile, pageNum, theFormat, thePage, formatChanged);
  880.     require(anErr == noErr, Forward_GXDespoolPage);
  881.     
  882.     hImageData = (*hGlobals)->hImageData;
  883.     check(hImageData != nil);
  884.     
  885.     // Fetch the paper type for paper that's supposed to be in the printer.  We use its
  886.     // dimensions to restrict the size of the image's page
  887.     // (This is the original format's paper type if unconfigured with a single doc paper type)
  888.     
  889.     GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
  890.  
  891.     // Scale the paperSize to the resolution of the device
  892.     {
  893.         Fixed        xScale;
  894.         Fixed        yScale;
  895.         gxMapping    theMapping;
  896.  
  897.         xScale = FixRatio(kHorizHighRes, 72);
  898.         yScale = FixRatio(kVertHighRes, 72);
  899.         
  900.         ResetMapping(&theMapping);
  901.         ScaleMapping(&theMapping, xScale, yScale, ff(0), ff(0));
  902.         
  903.         MapPoints(&theMapping, 2, (gxPoint *) &paperSize);
  904.     }
  905.     
  906.     // With the paper size scaled to the device resolution, we can now determine the max. page
  907.     // size to allow for this page
  908.     {
  909.         Fixed        paperHeight = paperSize.bottom - paperSize.top;
  910.         
  911.         if (paperHeight >= kMaxLegalPageHeight)
  912.             maxPageHeight = kMaxLegalPageHeight;
  913.         else
  914.             maxPageHeight = kMaxLetterPageHeight;
  915.     }
  916.     
  917.     // We adjust the pageSize gxRectangle so it's zero based and long word aligned. 
  918.     // We also align the device rect to be in line with what we expect for the LWSC, 
  919.     // convert it to old QuickDraw coordinates and store it into the globals for 
  920.     // use by SD_StartSendPage. 
  921.     
  922.     pageSize = (*hImageData)->pageSize;
  923.     
  924.     AlignPage(&pageSize, &deviceRect, maxPageHeight);
  925.     
  926.     (*hImageData)->pageSize = pageSize;
  927.     
  928.     anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 'RECT', 0, sizeof(Rect), &deviceRect);
  929.     nrequire(anErr, AddCollectionItemFails);
  930.     
  931.     
  932. /******* Clean-up *******/
  933.  
  934. AddCollectionItemFails:
  935. Forward_GXDespoolPage:
  936.     return(anErr);        
  937. }
  938. /* SD_DespoolPage */
  939.  
  940.  
  941. /****************************************************************************************
  942.  
  943.                             SD_SetupImageData
  944.                             
  945.     function:
  946.                 This routine is called when the Printing Manager wants us to initialize any
  947.                 imaging data that is specific to our type of printer.  In our case, we use
  948.                 just the default imaging information so all we do is retain the handle for
  949.                 later use.
  950.                 
  951.     parameters:                
  952.                 hImageData        Handle to the raster imaging data
  953.     returns:
  954.                 OSErr
  955.     
  956. ****************************************************************************************/
  957. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  958. {
  959.     OSErr                anErr;
  960.     SpecGlobalsHdl        hGlobals = GetMessageHandlerInstanceContext();
  961.     
  962.     check (hGlobals);
  963.     
  964.     // Retain the raster image data handle for later use 
  965.     (*hGlobals)->hImageData = hImageData;
  966.  
  967.     // Let others in the message chain do their SetupImageData function 
  968.     anErr = Forward_GXSetupImageData(hImageData);
  969.  
  970.     check(anErr == noErr);
  971.     return(anErr);
  972. }
  973. /* SD_SetupImageData */
  974.  
  975.  
  976. /****************************************************************************************
  977.  
  978.                             SD_OpenConnection
  979.                             
  980.     function:
  981.                 This routine is called when the Printing Manager sends the OpenConnection
  982.                 message.  We take this opportunity to locate a LaserWriter SC printer on
  983.                 the SCSI bus, and to make sure it's operational (i.e. no engine or memory
  984.                 failure).
  985.                 
  986.     parameters:        
  987.                 None
  988.                 
  989.     returns:
  990.                 OSErr
  991.     
  992. ****************************************************************************************/
  993. OSErr SD_OpenConnection(void)
  994. {
  995.     OSErr            anErr;
  996.     SCSenseData        senseData;
  997.     gxStatusRecord    *pStatus;
  998.  
  999.     // Tell user we're attempting to open a connection to the printer
  1000.     
  1001.     anErr = GXReportStatus(kTransmissionStatID, kOpeningConnectionStatIdx);
  1002.     require(anErr == noErr, GXReportStatus);
  1003.             
  1004.     // Try to locate the LaserWriter SC on the SCSI bus and make sure it's operational.
  1005.     // Keep trying to locate the printer until the user aborts (if it can't be found).
  1006.  
  1007.     anErr = LaserSC_OpenConnection();
  1008.     if (anErr == gxAioCantFindDevice)    //    T => Can't locate device; tell user to turn it on
  1009.     {
  1010.         // Now we set-up to alert the user that the printer cannot be found
  1011.         // Allocate a status record large enough to handle status with the largest buffer size. 
  1012.     
  1013.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
  1014.         anErr = MemError();
  1015.         require(anErr == noErr, NewPtrClear);
  1016.     
  1017.         // Initialize the appropriate fields within the status record 
  1018.         
  1019.         pStatus->statResId         = kTransmissionStatID;
  1020.         pStatus->statResIndex     = kCantFindPrinterStatIdx;
  1021.         pStatus->bufferLen         = gxDefaultStatusBufferSize;
  1022.  
  1023.         // Now display the alert to the user
  1024.         do
  1025.         {
  1026.             // Issue the alert to the user
  1027.             anErr = GXAlertTheUser(pStatus);
  1028.             if (anErr == noErr)
  1029.             {
  1030.                 // Try looking for the device again
  1031.                 anErr = LaserSC_OpenConnection();
  1032.             }
  1033.         }
  1034.         while ( (anErr == gxAioCantFindDevice) && (pStatus->dialogResult == nil) );
  1035.         
  1036.         // If the user dismissed the dialog, we are to abort the job
  1037.         if (pStatus->dialogResult != nil)
  1038.             anErr = gxPrUserAbortErr;
  1039.         
  1040.         // Always tell the Printing Finder Extension to dismiss the alert 
  1041.         {
  1042.             pStatus->statResId      =    gxUnivAlertStatusResourceId;
  1043.             pStatus->statResIndex =    gxUnivPrinterReadyIndex;
  1044.             
  1045.             // Tell the PFE to remove the alert
  1046.             GXAlertTheUser(pStatus);
  1047.         }
  1048.         
  1049.         // Kill the status pointer
  1050.         DisposPtr((Ptr) pStatus);
  1051.     }
  1052.     
  1053.     // If any error occurs at this point, then we must abort the open connection
  1054.     require(anErr == noErr, LaserSC_OpenConnection);
  1055.     
  1056.     // In case the printer has just been turned on or reset, issue a request sense 
  1057.     // command to clear the unit attention status.
  1058.     anErr = LaserSC_GetSenseData(&senseData);
  1059.     
  1060.     check(anErr == noErr);
  1061.     
  1062. /******* Clean-up *******/
  1063.  
  1064. LaserSC_OpenConnection:
  1065. NewPtrClear:
  1066. GXReportStatus:
  1067.     return(anErr);
  1068. }
  1069. /* SD_OpenConnection */
  1070.  
  1071.  
  1072. /****************************************************************************************
  1073.  
  1074.                             SD_CloseConnection
  1075.                             
  1076.     function:
  1077.                 This routine is called when the Printing Manager issues the CloseConnection
  1078.                 message.  We take this opportunity make sure that if we started printing a 
  1079.                 page at FinishSendPage time, that we force the page to be printed now, or
  1080.                 the job aborted.  We also place the printer into auto-feed mode
  1081.                 in case it was in manual feed mode.  This ensures the printer won't complain
  1082.                 about there not being any paper in the manual feed slot if we print again soon.  
  1083.                 Other than this, there is nothing else we need to do in order to "sever" a 
  1084.                 connection to an SC printer.
  1085.                 
  1086.     parameters:    
  1087.                 None
  1088.                 
  1089.     returns:
  1090.                 OSErr
  1091.     
  1092. ****************************************************************************************/
  1093. OSErr SD_CloseConnection (void)
  1094. {
  1095.     OSErr                anErr;
  1096.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1097.     
  1098.     // At this point in time we must make sure that if we previously printed a non-manual feed
  1099.     // page, the page printed successfully.  Here we force the page to be printed successfully,
  1100.     // unless the user aborts the job or we encounter a fatal printer problem. 
  1101.     
  1102.     if ( (*hGlobals)->printedAPage )
  1103.     {
  1104.         gxPaperType    thePaperType;
  1105.  
  1106.         thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
  1107.  
  1108.         // Wait for the page to print
  1109.         
  1110.         anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
  1111.  
  1112.         // Dispose of the cloned format and update the driver's globals
  1113.         
  1114.         (*hGlobals)->printedAPage = false;
  1115.         GXDisposeFormat((*hGlobals)->lastPageFormat);
  1116.  
  1117.         require(anErr == noErr, WaitForPageToPrint);
  1118.     }
  1119.  
  1120.     // Set printer to auto feed and non-buffered mode
  1121.     
  1122.     anErr = LaserSC_SetBuffandFeedMode(false, false);
  1123.     check(anErr == noErr);
  1124.  
  1125.  
  1126. /******* Clean-up *******/
  1127.  
  1128. WaitForPageToPrint:
  1129.     return(anErr);
  1130. }
  1131. /* SD_CloseConnection */
  1132.  
  1133.  
  1134. /****************************************************************************************
  1135.  
  1136.                             SD_StartSendPage
  1137.                             
  1138.     function:
  1139.                 This routine is called by the Printing Manager to signal the start of sending
  1140.                 a new page to the printer.  We first make sure that if we printed a previous
  1141.                 page, the page printed successfully.  Next we query the device to make sure that it's
  1142.                 ready to accept the next page. If there's a problem, we alert the user so he
  1143.                 can resolve it.  Finally, we set the page margins and dimensions in the printer,
  1144.                 and clear out the old frame buffer so there's no left over data.
  1145.                 
  1146.     parameters:                
  1147.                 pageFormat        format for the page to print
  1148.  
  1149.     returns:
  1150.                 OSErr
  1151.     
  1152. ****************************************************************************************/
  1153. OSErr SD_StartSendPage (gxFormat pageFormat)
  1154. {
  1155.     OSErr                anErr;
  1156.     short                leftMargin;                // top left corner of the page
  1157.     short                topMargin;
  1158.     short                bytesPerScanline;        // rowBytes and height of the page
  1159.     short                numScanlines;
  1160.     Rect                actualPage;                // unrotated page    
  1161.     short                deviceStatus;
  1162.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1163.     
  1164.     // Remember the pageFormat so we can access the manual feed setting at FinishSendPage, 
  1165.     // which is the time we actually tell the printer to print the page. 
  1166.  
  1167.     (*hGlobals)->pageFormat = pageFormat;
  1168.  
  1169.     // At this point in time we must make sure that if we previously printed a non-manual feed
  1170.     // page, the page printed successfully.  Here we force the page to be printed successfully,
  1171.     // unless the user aborts the job or we encounter a fatal printer problem. 
  1172.     
  1173.     if ( (*hGlobals)->printedAPage )
  1174.     {
  1175.         gxPaperType    thePaperType;
  1176.  
  1177.         thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
  1178.  
  1179.         // Wait for the page to print
  1180.         
  1181.         anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
  1182.  
  1183.         // Dispose of the cloned format and update the driver's globals
  1184.         
  1185.         (*hGlobals)->printedAPage = false;
  1186.         GXDisposeFormat((*hGlobals)->lastPageFormat);
  1187.  
  1188.         require(anErr == noErr, WaitForPageToPrint);
  1189.     }
  1190.  
  1191.     // Check to see if the device is ready to accept the next page of data 
  1192.  
  1193.     anErr = LaserSC_GetDeviceStatus(&deviceStatus);
  1194.     require(anErr == noErr, LaserSC_GetDeviceStatus);
  1195.     
  1196.     // Is the device not ready for more data? 
  1197.     if (deviceStatus != kGoodCondition)
  1198.     {
  1199.         long            printerProblem;
  1200.         short            dialogResult;
  1201.         Boolean            manualFeed;
  1202.         gxPaperType        thePaperType;
  1203.     
  1204.         // Determine if this is a manual feed job 
  1205.  
  1206.         thePaperType = GXGetFormatPaperType(pageFormat);
  1207.         anErr = IsManualFeedPaperType(thePaperType, &manualFeed);
  1208.         require(anErr == noErr, IsManualFeedPaperType);
  1209.  
  1210.         // Query the printer to determine its state 
  1211.  
  1212.         anErr = FindPrinterProblem(&printerProblem, nil);
  1213.         require(anErr == noErr, FindPrinterProblem);
  1214.         
  1215.         // If the printer is out of paper and we're doing a manual feed job, then don't 
  1216.         // alert the user now.  Wait until we actually try to print a page (it gives him more 
  1217.         // time to put the paper in - refer to SD_FinishSendPage). 
  1218.  
  1219.         if ( (GetStatResIndex(printerProblem) != kOutOfPaperStatIdx) || !manualFeed )
  1220.         {
  1221.             // Based upon the state of the printer, inform/alert the user to the problem 
  1222.             // so he can correct it. 
  1223.  
  1224.             anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
  1225.             require(anErr == noErr, ResolvePrinterProblem);
  1226.         }
  1227.     }
  1228.  
  1229.     // If we get here, the printer must be ready for data.  Tell user we're preparing the data. 
  1230.  
  1231.     anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
  1232.     require(anErr == noErr, GXReportStatus);
  1233.         
  1234.     // Now we need to set the printer's page margins, as well as the page dimensions. 
  1235.     // We compute the needed values from the deviceRect we initialized at despool page 
  1236.     // time. Recall that the deviceRect represents the imaging gxRectangle within the 
  1237.     // printers RAM. 
  1238.     
  1239.     GetCollectionItem(GXGetFormatCollection(pageFormat), 'RECT', 0, nil, &actualPage);
  1240.     leftMargin             =     actualPage.left >> 3;                                // left margin is specified in number of bytes 
  1241.     topMargin             =     actualPage.top;                                        // top margin is specified in number of scan lines 
  1242.     bytesPerScanline     =     (actualPage.right - actualPage.left) >> 3;    // bytesPerScanline is the number of bytes in a single scan line 
  1243.     numScanlines         =     actualPage.bottom - actualPage.top;                // numScanlines is just the line height of the device gxRectangle 
  1244.     
  1245.     // Force the margins to be at least as large as the minimum supported by the SC printer 
  1246.  
  1247.     if (topMargin < kMinSCTopMargin)
  1248.         topMargin = kMinSCTopMargin;
  1249.  
  1250.     if (leftMargin < kMinSCLeftMargin)
  1251.         leftMargin = kMinSCLeftMargin;
  1252.         
  1253.     // Set the top and left margin for the printer 
  1254.  
  1255.     anErr = LaserSC_SetPageMargins(leftMargin, topMargin);
  1256.     require(anErr == noErr, LaserSC_SetPageMargins);
  1257.     
  1258.     // Set the page dimensions for the printer 
  1259.  
  1260.     anErr = LaserSC_SetPageDimensions(bytesPerScanline, numScanlines);
  1261.     require(anErr == noErr, LaserSC_SetPageDimensions);
  1262.             
  1263.     // Make sure the printers page frame buffer is cleared out.  We offset the 
  1264.     // actualPage gxRectangle because the printer assumes the top left corner of the 
  1265.     // imaging area gxRectangle is (0, 0). 
  1266.     
  1267.     OffsetRect(&actualPage, -actualPage.left, -actualPage.top);
  1268.     anErr = LaserSC_ClearBits(&actualPage);
  1269.  
  1270.     check(anErr == noErr);
  1271.     
  1272.     
  1273. /******* Cleanup *******/
  1274.  
  1275. LaserSC_SetPageDimensions:
  1276. LaserSC_SetPageMargins:
  1277. GXReportStatus:
  1278. ResolvePrinterProblem:
  1279. FindPrinterProblem:
  1280. IsManualFeedPaperType:
  1281. LaserSC_GetDeviceStatus:
  1282. WaitForPageToPrint:
  1283.     return(anErr);
  1284. }
  1285. /* SD_StartSendPage */
  1286.  
  1287.  
  1288. /****************************************************************************************
  1289.  
  1290.                             SD_FinishSendPage
  1291.                             
  1292.     function:
  1293.                 This routine is called by the Printing Manager to signal that we're at the
  1294.                 end of the current page.  If we're not processing a manual feed job, then we
  1295.                 simply print the page that's in the printers RAM and alert the user to any
  1296.                 errors that result.  If it's a manual feed job, then we first prompt the user
  1297.                 to put paper in the printer if there isn't any paper in there currently.  For
  1298.                 auto-feed jobs, we start printing now, but don't wait for it to complete
  1299.                 until the next StartSendPage or CloseConnection message is issued.
  1300.                 
  1301.     parameters:    
  1302.                 None
  1303.                 
  1304.     returns:
  1305.                 OSErr
  1306.     
  1307. ****************************************************************************************/
  1308. OSErr SD_FinishSendPage (void)
  1309. {
  1310.     OSErr                anErr;
  1311.     Boolean            manualFeed;
  1312.     gxPaperType        thePaperType;
  1313.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1314.     
  1315.     // Determine if this is a manual feed job 
  1316.  
  1317.     thePaperType = GXGetFormatPaperType((*hGlobals)->pageFormat);
  1318.     anErr = IsManualFeedPaperType(thePaperType, &manualFeed);
  1319.     require(anErr == noErr, IsManualFeedPaperType);
  1320.     
  1321.     // Set the manual feed mode of the printer based upon the paper configuration, and set the 
  1322.     // printer's buffered mode so that the SC Print and Clear Bits commands return immediately 
  1323.     // without waiting for the commands to complete. 
  1324.     
  1325.     anErr = LaserSC_SetBuffandFeedMode(manualFeed, true);
  1326.     require(anErr == noErr, LaserSC_SetBuffandFeedMode);
  1327.  
  1328.     // Indicate that we are now printing a page
  1329.     
  1330.     anErr = GXReportStatus(kTransmissionStatID, kPrintingPageStatIdx);
  1331.     require(anErr == noErr, GXReportStatus);
  1332.  
  1333.     // Now we issue the Print command to start printing the buffered page.  If we're not printing a
  1334.     // manual feed job, then we just continue on and will check to make sure the page
  1335.     // completed printing at the next StartSendPage message or the next CloseConnection message.
  1336.     // If we're printing a manual feed job and there isn't any paper in the printer, then the printer 
  1337.     // will return an "end-of-media" error and we will alert the user to put paper in 
  1338.     // the printer. We continue looping, re-issuing the Print command as needed until 
  1339.     // the page is either printed, or the user aborts the job. 
  1340.     
  1341.     // Issue the print command to start the page printing 
  1342.  
  1343.     anErr = LaserSC_PrintPage(    false,             // T => print at 8 page per minute rate; F => print normal rate
  1344.                                         false);             // T => clear printer's page buffer while printing; F => don't clear buffer
  1345.     require(anErr == noErr, LaserSC_PrintPage);
  1346.  
  1347.     // If this is a manual feed job, wait for the page to print since we need to tell the user to put paper in the printer.
  1348.     if (manualFeed)
  1349.     {
  1350.         anErr = WaitForPageToPrint(manualFeed, thePaperType);
  1351.         check(anErr == noErr);
  1352.  
  1353.         (*hGlobals)->printedAPage = false;    //    No need to check on the printed page later
  1354.     }
  1355.     else    //    T => Remember that we've started printing a page so we can check on it later
  1356.     {
  1357.         gxFormat    theFormat;
  1358.         
  1359.         (*hGlobals)->printedAPage = true;
  1360.         
  1361.         // Clone the format so we can reference it again at the next StartSendPage or CloseConnection time.  The
  1362.         // driver disposes of the clone at that time.
  1363.         
  1364.         theFormat = GXCloneFormat((*hGlobals)->pageFormat);
  1365.         (*hGlobals)->lastPageFormat = theFormat;
  1366.     }
  1367.     
  1368.     
  1369. /******* Cleanup *******/
  1370.  
  1371. LaserSC_PrintPage:
  1372. GXReportStatus:
  1373. LaserSC_SetBuffandFeedMode:
  1374. IsManualFeedPaperType:
  1375.     return(anErr);
  1376. }
  1377. /* SD_FinishSendPage */
  1378.  
  1379.  
  1380. /****************************************************************************************
  1381.  
  1382.                             SD_WriteData
  1383.                             
  1384.     function:
  1385.                 This routine is called by the Printing Manager to send data to the device.
  1386.                 This driver uses the routine to complete, or save in globals temporarily, 
  1387.                 the next SCSI command to be issued to the device.  It determines whether to
  1388.                 do the command now or save it for later (to be done in SD_CheckStatus or 
  1389.                 SD_GetDeviceStatus) by examining which SCSI command is to be executed.
  1390.                 
  1391.                 If the pData parameter is non-nil, then the routine assumes pData references
  1392.                 a SCSI command to be issued to the device, and the length parameter specifies
  1393.                 the size of the command.  If the SCSI command does not require additional
  1394.                 data to be sent/received from the device, then this routine calls the SCSI Manager
  1395.                 routines SCSIGet, SCSISelect, and SCSICmd in order to complete the SCSI command
  1396.                 during this call.  If the SCSI command requires an additional data transfer, 
  1397.                 then the SCSI command is saved in the driver's globals, and will be issued
  1398.                 on a subsequent call to SD_CheckStatus or SD_GetDeviceStatus (when the other
  1399.                 portion of the data transfer is performed) and the command can be completed.
  1400.                 
  1401.     parameters:        
  1402.                 pData            pointer to SCSI command to perform
  1403.                 length        size of the SCSI command (bytes)
  1404.                 
  1405.     returns:
  1406.                 OSErr
  1407.  
  1408. ****************************************************************************************/
  1409. OSErr SD_WriteData(Ptr pData, long length)
  1410. {
  1411.     OSErr            anErr = noErr;
  1412.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1413.     
  1414.     // Are we to issue a new SCSI command to the device?
  1415.     if (pData != nil)
  1416.     {
  1417.         short        scsiStatus;
  1418.         short        message;
  1419.  
  1420.         // Remember what timeout value to use for this printer command when we complete the op.
  1421.         (*hGlobals)->timeoutForSCSIComplete = LaserSC_GetTimeoutForSCSICmnd(*((short *) pData));
  1422.         
  1423.         // If this SCSI command is one we can complete now (i.e. no other data transfer is
  1424.         // required), then we do it now. Otherwise, we save the command in the driver's
  1425.         // globals and it will be executed on a subsequent call to SD_CheckStatus or
  1426.         // SD_GetDeviceStatus.
  1427.         
  1428.         switch ( *((short *) pData) )
  1429.         {
  1430.              case kSCPrinterReady:        //    These SC commands consist only of SCSI commands; do them now
  1431.             case kSCResetPrinter:
  1432.             case kSCPrint:
  1433.             
  1434.                 // Get control of the SCSI bus before issuing the command
  1435.                 anErr = SCSIGet();
  1436.                 require(anErr == noErr, SCSIGetFails);
  1437.                 
  1438.                 // Select the target device on the SCSI bus
  1439.                 anErr = SCSISelect((*hGlobals)->deviceNum);
  1440.                 require(anErr == noErr, SCSISelectFails);
  1441.                     
  1442.                 // Now send the command to the device
  1443.                 SCSICmd(pData, length);
  1444.  
  1445.                 // Now force completion of the SCSI command
  1446.                 anErr = SCSIComplete(&scsiStatus, &message, (*hGlobals)->timeoutForSCSIComplete);
  1447.                 require(anErr == noErr, SCSICompleteFails);
  1448.  
  1449.                 // Remember the last SCSI status in the globals
  1450.                 (*hGlobals)->lastSCSIStatus = scsiStatus;
  1451.                 
  1452.                 break;
  1453.             
  1454.             default:                            //    All other SC commands require some data transfer with the SCSI command
  1455.                 
  1456.                 // Save the SCSI command in the driver's globals for later use
  1457.                 BlockMove(pData, (Ptr) (*hGlobals)->scsiCommand, length);
  1458.                 
  1459.                 // If we're starting a DrawBits command, make sure the appropriate globals are initialized
  1460.                 if ( *((short *) pData) == kSCDrawBits )
  1461.                     (*hGlobals)->haveDrawBitsParams = false;
  1462.         }
  1463.         
  1464.     }
  1465.     
  1466.  
  1467. /******* Clean-up *******/
  1468.  
  1469. SCSISelectFails:
  1470. SCSIGetFails:
  1471. SCSICompleteFails:
  1472.     return(anErr);
  1473. }
  1474. /* SD_WriteData */
  1475.  
  1476.  
  1477. /****************************************************************************************
  1478.  
  1479.                             SD_CheckStatus
  1480.                             
  1481.     function:
  1482.                 This routine is called by the Printing Manager to mark places in which to check
  1483.                 the status of the device.  This driver does not use this routine to retrieve 
  1484.                 the status of the device. Rather, it uses the routine to send data to the 
  1485.                 device.
  1486.                 
  1487.                 The pData parameter points to the data to be sent, and the length parameter
  1488.                 specifies how many bytes to transfer.  The statusType parameter specifies
  1489.                 the number of bytes to transfer in each SCSI data burst, and whether we should
  1490.                 use the SCSIWrite or SCSIWBlind routines to accomplish the data transfer.  If
  1491.                 statusType is positive, then we should use SCSIWrite; otherwise we use should
  1492.                 SCSIWBlind.  The absolute value of statusType specifies the number of bytes to
  1493.                 transfer in each SCSI data burst.
  1494.                 
  1495.                 When this routine is called for any SCSI command other than DrawBits, the command
  1496.                 is completed during this call.  If the call is for the SC DrawBits command, then
  1497.                 we only complete the command if the routine is being called to with the gxBitmap
  1498.                 data to be sent to the device (when the global variable haveDrawBitsParams is
  1499.                 true).
  1500.                 
  1501.     parameters:    
  1502.                 pData            pointer to data to send to device
  1503.                 length        number of bytes to send to the device
  1504.                 statusType    < 0 => do transfer using SCSIWBlind
  1505.                                 >= 0 => do transfer using SCSIWrite
  1506.                                 abs(statusType) is number of bytes to transfer in each SCSI data burst
  1507.                 owner            indicates who generated the CheckStatus request
  1508.                 
  1509.     returns:
  1510.                 OSErr
  1511.  
  1512. ****************************************************************************************/
  1513. OSErr SD_CheckStatus(Ptr pData, long length, short statusType, OSType owner)
  1514. {
  1515.     OSErr                anErr = noErr;
  1516.     SCSIInstr            tibProgram[9];
  1517.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  1518.     SpecGlobalsPtr        pGlobals;
  1519.     Boolean                doCmndNow = true;
  1520.     
  1521.     HLock((Handle) hGlobals);
  1522.     pGlobals = *hGlobals;
  1523.         
  1524.     // Is this a CheckStatus request that we generated?
  1525.     if (owner == kDrvrCreatorType)
  1526.     {
  1527.         // Check to see if it's a DrawBits command and that we now have the gxBitmap data
  1528.         if ( pGlobals->scsiCommand[0] == kSCDrawBits )
  1529.         {
  1530.             // Have we already received the parameters to the DrawBits command?
  1531.             if ( pGlobals->haveDrawBitsParams )
  1532.             {
  1533.                 // Get control of the SCSI bus before issuing the command
  1534.                 anErr = SCSIGet();
  1535.                 require(anErr == noErr, SCSIGetFails1);
  1536.                 
  1537.                 // Select the target device on the SCSI bus
  1538.                 anErr = SCSISelect(pGlobals->deviceNum);
  1539.                 require(anErr == noErr, SCSISelectFails1);
  1540.                     
  1541.                 // Now send the command to the device
  1542.                 SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1543.                 
  1544.                 // Now we generate a SCSI Manager TIB program to send the parameters to the DrawBits command
  1545.                 GenTIBProgram(tibProgram, (Ptr) pGlobals->drawbitsParams, 10, 10);
  1546.                 
  1547.                 // Send the DrawBits parameters to the device
  1548.                 anErr = SCSIWrite((Ptr) tibProgram);
  1549.                 require(anErr == noErr, SCSIWriteFails1);
  1550.             }
  1551.             else    //    T => Client is calling us with the DrawBits parameters; save them for later use
  1552.             {
  1553.                 BlockMove(pData, (Ptr) pGlobals->drawbitsParams, length);
  1554.                 pGlobals->haveDrawBitsParams = true;
  1555.                 doCmndNow = false;
  1556.             }
  1557.         }
  1558.         else    //    T => not a DrawBits command. Complete the command during this call
  1559.         {
  1560.             // Get control of the SCSI bus before issuing the command
  1561.             anErr = SCSIGet();
  1562.             require(anErr == noErr, SCSIGetFails2);
  1563.             
  1564.             // Select the target device on the SCSI bus
  1565.             anErr = SCSISelect(pGlobals->deviceNum);
  1566.             require(anErr == noErr, SCSISelectFails2);
  1567.                 
  1568.             // Now send the command to the device
  1569.             SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1570.         }
  1571.         
  1572.         // Are we completing the command during this call?
  1573.         if (doCmndNow)
  1574.         {
  1575.             short        scsiStatus;
  1576.             short        message;
  1577.  
  1578.             // Create a SCSI Manager TIB program to perform the last piece of the SCSI data transfer
  1579.             GenTIBProgram(tibProgram, pData, length, abs(statusType));
  1580.             
  1581.             // Determine which SCSI Manager command to perform and send the data
  1582.             if (statusType >= 0)
  1583.             {
  1584.                 anErr = SCSIWrite((Ptr) tibProgram);
  1585.                 require(anErr == noErr, SCSIWriteFails2);
  1586.             }
  1587.             else    //    T => Do data transfer using a blind transfer
  1588.             {
  1589.                 anErr = SCSIWBlind((Ptr) tibProgram);
  1590.                 require(anErr == noErr, SCSIWBlindFails);
  1591.             }
  1592.             
  1593.             // Now force completion of the SCSI command
  1594.             anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
  1595.             require(anErr == noErr, SCSICompleteFails);
  1596.  
  1597.             // Remember the last SCSI status in the globals
  1598.             pGlobals->lastSCSIStatus = scsiStatus;
  1599.         }
  1600.         // else - We received the DrawBits parameters; can't do command now
  1601.     }
  1602.     else    //    T => This is not our CheckStatus request; pass it along the message chain
  1603.     {
  1604.         anErr = Forward_GXCheckStatus(pData, length, statusType, owner);
  1605.         require(anErr == noErr, Forward_GXCheckStatusFails);
  1606.     }
  1607.  
  1608. /******* Clean-up *******/
  1609.  
  1610. SCSICompleteFails:
  1611. SCSIWBlindFails:
  1612. SCSIWriteFails2:
  1613. SCSIWriteFails1:
  1614. SCSISelectFails2:
  1615. SCSIGetFails2:
  1616. SCSISelectFails1:
  1617. SCSIGetFails1:
  1618. Forward_GXCheckStatusFails:
  1619.     HUnlock((Handle) hGlobals);
  1620.  
  1621.     return(anErr);
  1622. }
  1623. /* SD_CheckStatus */
  1624.  
  1625.  
  1626. /****************************************************************************************
  1627.  
  1628.                             SD_GetDeviceStatus
  1629.                             
  1630.     function:
  1631.                 This routine is called by the Printing Manager to query the current status
  1632.                 of the device.  This driver does not use this routine to retrieve 
  1633.                 the status of the device. Rather, it uses the routine to retrieve the
  1634.                 status value returned from last SCSI Manager SCSIComplete command and to
  1635.                 retrieve data from the device.
  1636.                 
  1637.                 If the responseData pointer is non-nil, then the routine will attempt to
  1638.                 read data from the printer.  In this case, responseData points to the buffer
  1639.                 to hold the data received; responseSize specifies the number of bytes to
  1640.                 read; and cmdSize specifies the number of bytes to transfer in each SCSI data 
  1641.                 burst, and whether we should use the SCSIRead or SCSIRBlind routines to 
  1642.                 accomplish the data transfer.  If cmdSize is positive, then we should use 
  1643.                 SCSIRead; otherwise we use should SCSIRBlind.  The absolute value of 
  1644.                 cmdSize specifies the number of bytes to transfer in each SCSI data burst.
  1645.                 
  1646.                 If the responseData pointer is nil, then the routine returns the status 
  1647.                 value from the last SCSI Manager SCSIComplete command.  All other
  1648.                 parameters are ignored.
  1649.                 
  1650.     parameters:    
  1651.                 cmdData            not used
  1652.                 cmdSize            if responseData != nil then
  1653.                                     < 0 => do transfer using SCSIRBlind
  1654.                                     >= 0 => do transfer using SCSIRead
  1655.                                     abs(cmdSize) is number of bytes to transfer in each SCSI data burst
  1656.                 responseData    if responseData != nil, read data from device; otherwise ignored
  1657.                 responseSize    if responseData != nil, specifies the number of bytes to read from device;
  1658.                                     Otherwise, returns the status from the last SCSIComplete call
  1659.                 termination        not used
  1660.                 
  1661.     returns:
  1662.                 OSErr
  1663.  
  1664. ****************************************************************************************/
  1665. OSErr SD_GetDeviceStatus(Ptr cmdData, long cmdSize, Ptr responseData, long *responseSize, Str255 termination)
  1666. {
  1667.     #pragma unused (cmdData, termination)
  1668.     
  1669.     OSErr                anErr = noErr;
  1670.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  1671.     SCSIInstr            tibProgram[9];
  1672.     SpecGlobalsPtr        pGlobals;
  1673.     
  1674.     HLock((Handle) hGlobals);
  1675.     pGlobals = *hGlobals;
  1676.         
  1677.     // Are we to read some data from the device?
  1678.     if (responseData != nil)
  1679.     {
  1680.         short        scsiStatus;
  1681.         short        message;
  1682.  
  1683.         // Get control of the SCSI bus before issuing the command
  1684.         anErr = SCSIGet();
  1685.         require(anErr == noErr, SCSIGetFails);
  1686.         
  1687.         // Select the target device on the SCSI bus
  1688.         anErr = SCSISelect(pGlobals->deviceNum);
  1689.         require(anErr == noErr, SCSISelectFails);
  1690.             
  1691.         // Now send the command to the device
  1692.         SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1693.  
  1694.         // Create a SCSI Manager TIB program to perform the SCSI data transfer
  1695.         GenTIBProgram(tibProgram, responseData, *responseSize, abs(cmdSize));
  1696.         
  1697.         // Determine which SCSI Manager command to perform and read the data
  1698.         if (cmdSize >= 0)
  1699.         {
  1700.             anErr = SCSIRead((Ptr) tibProgram);
  1701.             require(anErr == noErr, SCSIReadFails);
  1702.         }
  1703.         else    //    T => Do data transfer using a blind transfer
  1704.         {
  1705.             anErr = SCSIRBlind((Ptr) tibProgram);
  1706.             require(anErr == noErr, SCSIRBlindFails);
  1707.         }
  1708.             
  1709.         // Now force completion of the SCSI command
  1710.         anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
  1711.         require(anErr == noErr, SCSICompleteFails);
  1712.  
  1713.         // Remember the last SCSI status in the globals
  1714.         pGlobals->lastSCSIStatus = scsiStatus;
  1715.     }
  1716.     else    // T => Return the last SCSI status in the responseSize parameter
  1717.         *responseSize = (*hGlobals)->lastSCSIStatus;
  1718.     
  1719.  
  1720. /******* Clean-up *******/
  1721.  
  1722. SCSICompleteFails:
  1723. SCSIRBlindFails:
  1724. SCSIReadFails:
  1725. SCSISelectFails:
  1726. SCSIGetFails:
  1727.     HUnlock((Handle) hGlobals);
  1728.  
  1729.     return(anErr);    
  1730. }
  1731. /* SD_GetDeviceStatus */
  1732.  
  1733.  
  1734. /****************************************************************************************
  1735.  
  1736.                             SD_CreateImageFile
  1737.                             
  1738.     function:
  1739.                 This routine is called by the Printing Manager when a new image file is to
  1740.                 be created.  This driver overrides this message for debugging purposes only.
  1741.                 If the SCImageFileDebugFlag is defined, we forward the message with a 
  1742.                 new set of imageFileOptions, namely "makeImageFile + entireFile".  This forces the
  1743.                 Universal Driver to image the image file.  This allows us to test the proper
  1744.                 generation of image files.  If the compile time flag is not set, then the 
  1745.                 this routine is a no-op; it simply forwards the message on to others in the
  1746.                 message chain.
  1747.                 
  1748.     parameters:    
  1749.                 fileSpec                file spec for the image file
  1750.                 imageFileOptions    options to apply to the creation of the image file
  1751.                 theImageFile        a Printing Manager reference to the image file
  1752.                 
  1753.     returns:
  1754.                 OSErr
  1755.  
  1756. ****************************************************************************************/
  1757. OSErr SD_CreateImageFile(FSSpecPtr fileSpec, long imageFileOptions, long *theImageFile)
  1758. {
  1759.     OSErr        anErr = noErr;
  1760.     
  1761.     #ifdef SCImageFileDebugFlag
  1762.         anErr = Forward_GXCreateImageFile(fileSpec, makeImageFile + entireFile, theImageFile);
  1763.     #else
  1764.         anErr = Forward_GXCreateImageFile(fileSpec, imageFileOptions, theImageFile);
  1765.     #endif
  1766.     
  1767.     check(anErr == noErr);
  1768.     return(anErr);
  1769. }
  1770. /* SD_CreateImageFile */
  1771.  
  1772.  
  1773. /****************************************************************************************
  1774.  
  1775.                             SD_FetchTaggedData
  1776.                             
  1777.     function:
  1778.                 This routine is called by the Printing Manager when a a resource is fetched
  1779.                 from some resource file.  This driver overrides this message to determine
  1780.                 when someone is fetching the gxRasterPrefsType resource.  If this resource
  1781.                 is being fetched, and the job we're processing is not best quality, then
  1782.                 we disable the halftoning feature in the resource.  This should make the
  1783.                 printing of just graphics a little bit faster.
  1784.                 
  1785.     parameters:    
  1786.                 rsrcType            type of the resource being retrieved
  1787.                 rsrcID            resource ID of the resource being retrieved
  1788.                 theRsrc            handle to the resource retrieved
  1789.                 owner                indicates who is issuing the request; only look at owners == 'drvr'
  1790.                 
  1791.     returns:
  1792.                 OSErr
  1793.  
  1794. ****************************************************************************************/
  1795. OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
  1796. {
  1797.     OSErr        anErr;
  1798.     
  1799.     // First fetch the actual resource
  1800.     anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
  1801.     require(anErr == noErr, FetchTaggedData);
  1802.     
  1803.     if (    (owner == 'drvr')                    &&        //    T => Fetching a driver resource
  1804.             (rsrcType == gxRasterPrefsType)    &&        //    T => type is 'rdip'
  1805.             (rsrcID == gxRasterPrefsID)        &&        //    T => ID is 0
  1806.             ( !JobIsBestQuality() )                    //    T => Doing rough output
  1807.         )
  1808.     {
  1809.         ( (gxRasterPrefsPtr) **theRsrc)->planeSetup[0].planeOptions = gxDontSetHalftone;
  1810.     }
  1811.  
  1812.  
  1813. /******* Clean-up *******/
  1814.  
  1815. FetchTaggedData:
  1816.     return(anErr);
  1817. }
  1818. /* SD_FetchTaggedData */
  1819.  
  1820.  
  1821. /****************************************************************************************
  1822.  
  1823.                             SD_RasterDataIn
  1824.                             
  1825.     function:
  1826.                 This routine is called by the Printing Manager when it has completed rendering
  1827.                 a single portion of a raster page.  It calls this routine to send the gxBitmap
  1828.                 to the device.  The data for the SC does not require any special packaging
  1829.                 other than that the gxRectangle to draw in must be converted to a QuickDraw
  1830.                 gxRectangle and it's left edge must be zero based (this is what the SC engine
  1831.                 expects, otherwise it returns an error 5).  We update the status display
  1832.                 and send the data to the device.
  1833.                 
  1834.     parameters:        
  1835.                 hOffscreen            handle to the structure which references the offscreen gxBitmap of data
  1836.                 bandRect                gxRectangle in which to place the data on the page
  1837.                 dirtyRects            dirty area within that gxRectangle
  1838.                 
  1839.     returns:
  1840.                 OSErr
  1841.  
  1842. ****************************************************************************************/
  1843. OSErr SD_RasterDataIn (gxOffscreenHdl hOffscreen, gxRectangle *bandRect, gxRectangle *dirtyRect)
  1844. {
  1845.  
  1846.     OSErr            anErr;
  1847.     Rect            rDirty;
  1848.     char            lockState;
  1849.     
  1850.     
  1851.     // Create the boundary gxRectangle in which to "draw" the gxBitmap on the printer 
  1852.  
  1853.     SetRect(&rDirty,     F2S(bandRect->left),
  1854.                             F2S(dirtyRect->top),
  1855.                             F2S(bandRect->right),
  1856.                             F2S(dirtyRect->bottom) );
  1857.     
  1858.     // Make sure this gxRectangle's left edge is zero based (required by SC) 
  1859.  
  1860.     rDirty.right -= rDirty.left;
  1861.     rDirty.left = 0;
  1862.     
  1863.     // Give the app. a chance to run 
  1864.  
  1865.     anErr = GXJobIdle();
  1866.     require(anErr == noErr, GXJobIdle);
  1867.     
  1868.     // Update the status display to indicate that we're sending data to the printer         
  1869.  
  1870.     anErr = GXReportStatus(kTransmissionStatID, kSendingPartOfPageStatIdx);
  1871.     require(anErr == noErr, GXReportStatus);
  1872.     
  1873.     // Make sure the offscreen gxBitmap is locked down before we draw 
  1874.  
  1875.     lockState = HGetState((Handle) hOffscreen);
  1876.     HLock((Handle) hOffscreen);
  1877.     {
  1878.         gxBitmap        *pBitmap;
  1879.         Ptr            image;
  1880.         
  1881.         pBitmap = &(*hOffscreen)->thePlanes[0].theBits;
  1882.         image = pBitmap->image;
  1883.         image += pBitmap->rowBytes * (rDirty.top - F2S(bandRect->top));
  1884.         anErr = LaserSC_DrawBits(image, &rDirty, pBitmap->rowBytes, srcCopy);
  1885.     }
  1886.     HSetState((Handle) hOffscreen, lockState);
  1887.  
  1888.     require(anErr == noErr, LaserSC_DrawBits);
  1889.     
  1890.     // Update the status display to indicate that we're preparing the next chunk of data         
  1891.  
  1892.     anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
  1893.     require(anErr == noErr, ReportStatus2);
  1894.         
  1895.     
  1896. /******* Cleanup *******/
  1897.  
  1898. ReportStatus2:
  1899. LaserSC_DrawBits:
  1900. GXReportStatus:
  1901. GXJobIdle:
  1902.     return(anErr);
  1903. }
  1904. /* SD_RasterDataIn */
  1905.  
  1906. /****************************************************************************************
  1907.  
  1908.                             SD_DoesPaperFit
  1909.                             
  1910.     function:
  1911.                 This routine is called by the Printing Manager when the user selects the input
  1912.                 trays dialog from the printing menu.  The driver checks the page dimensions to
  1913.                 see if it is physically possible to store the paper in the printer.
  1914.                 
  1915.     parameters:        
  1916.                 paper            papertype to check
  1917.                 fits            (returned)  true if dimensions fit, false otherwise
  1918.                 
  1919.     returns:
  1920.                 noErr
  1921.  
  1922. ****************************************************************************************/
  1923. OSErr SD_DoesPaperFit (gxPaperType paper, Boolean *fits)
  1924. {
  1925.     gxRectangle        paperSize;
  1926.     fixed            paperWidth, paperHeight, tempFixed;
  1927.  
  1928.      GXGetPaperTypeDimensions(paper, nil, &paperSize);    
  1929.     paperWidth     =    paperSize.right - paperSize.left;
  1930.     paperHeight =    paperSize.bottom - paperSize.top;
  1931.     
  1932.     *fits = false;
  1933.     
  1934. // for simplicity, make sure paperHeight >= paperWidth
  1935.     
  1936.     if ( paperWidth > paperHeight ) {
  1937.         tempFixed = paperWidth;
  1938.         paperWidth = paperHeight;
  1939.         paperHeight = tempFixed;
  1940.         }
  1941.  
  1942. // the SC supports 5 paper sizes
  1943. // widths range from kEnvelopeWidth to kUSLetterWidth
  1944. // heights range from kEnvelopeHeight to kUSLegalHeight
  1945.  
  1946.     if (( paperWidth >= kEnvelopeWidth )  && ( paperWidth <= kUSLetterWidth ))
  1947.         if (( paperHeight >= kEnvelopeHeight ) && (paperHeight <= kUSLegalHeight )) {
  1948.         
  1949.             if ( paperWidth == kUSLetterWidth ) {
  1950.                 if (( paperHeight == kUSLetterHeight ) || ( paperHeight == kUSLegalHeight ))
  1951.                     *fits = true;
  1952.                 }
  1953.             else if (( paperWidth == kA4LetterWidth ) && ( paperHeight == kA4LetterHeight ))
  1954.                 *fits = true;
  1955.             else if (( paperWidth == kB5LetterWidth ) && ( paperHeight == kB5LetterHeight ))
  1956.                 *fits = true;
  1957.             else if (( paperWidth == kEnvelopeWidth ) && ( paperHeight == kEnvelopeHeight ))
  1958.                 *fits = true;
  1959.             }
  1960.     
  1961.     return( noErr );
  1962. }
  1963.